package cn.wingware.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

public class MemcachedUtil {

	private static final Log log = LogFactory.getLog(MemcachedUtil.class);

	private static MemcachedUtil instance = null;

	private static MemCachedClient mcc = null;

	private static int sessionTimeout = 1800000; // 超时时间

	private static SockIOPool pool = null;

	private static String poolName = "memsock";

	private boolean isNotConnection = false;

	private static Properties props = null;

	private static Object lock = new Object();

	private static boolean useflag = true;

	public static boolean useMemcache(boolean f) {
		boolean retF = true;
		try {
			synchronized (lock) {
				useflag = f;
			}
		} catch (Exception e) {
			retF = false;
		}
		return retF;
	}

	public static synchronized MemcachedUtil getInstance() {

		if (instance == null) {
			synchronized (lock) {
				if (instance == null)
					instance = new MemcachedUtil();
			}
		}
		return instance;
	}

	public MemcachedUtil() {
		InputStream ins = null;
		try {
			if (props == null || props.isEmpty() || pool == null) {
				ins = this.getClass().getClassLoader().getResourceAsStream("ams-memcached.properties");
				props = new Properties();
				props.load(ins);
				log.debug("session_properties=ams-memcached.properties|" + props);
				initSockIOPool(props);
				sessionTimeout = InnerConvertUtil.getIntProperty(props,"sessiontimeout", 1800000);
			}
		} catch (Exception e) {
			log.warn("MemCached Exception", e);
		} finally {
			try {
				if (ins != null)
					ins.close();
			} catch (IOException e) {
				log.warn("close inputstream error!", e);
			}
		}
	}

	private static void initSockIOPool(Properties props) {
		String serverlist = props.getProperty("serverlist");
		poolName = props.getProperty("poolname", "memsock");
		String[] servers = serverlist.split(",");
		pool = SockIOPool.getInstance(poolName);
		log.debug("SockIOPool = " + pool);
		pool.setServers(servers);
		pool.setFailover(InnerConvertUtil.getBooleanProperty(props, "failover",true));
		pool.setInitConn(InnerConvertUtil.getIntProperty(props, "initconn",10));
		pool.setMinConn(InnerConvertUtil.getIntProperty(props, "minconn", 5));
		pool.setMaxConn(InnerConvertUtil.getIntProperty(props, "maxconn", 250));
		pool.setMaintSleep(InnerConvertUtil.getIntProperty(props, "maintsleep",30));
		pool.setNagle(InnerConvertUtil.getBooleanProperty(props, "nagle", false));
		pool.setSocketTO(InnerConvertUtil.getIntProperty(props, "socketto",3000));
		pool.setAliveCheck(InnerConvertUtil.getBooleanProperty(props,"alivecheck", true));
		pool.initialize();
	}

	public Object getAttribute(String id) {
		long start = System.currentTimeMillis();

		Object obj = null;
		if (useflag) {
			getMemCachedClient();
			obj = mcc.get(id);
		}
		long end = System.currentTimeMillis();
		log.debug("get id=" + id + "  obj=" + obj + " use time=" + (end - start));
		return obj;
	}
	
	public Object getAttribute(String id,String v) {
		long start = System.currentTimeMillis();
		Object obj = null;
		if (useflag) {
			getMemCachedClient();
			obj = mcc.get(id);
			if(obj!=null) {
				obj=((Map)obj).get(v);
			}
		}
		long end = System.currentTimeMillis();
		log.debug("get id=" + id + "  obj=" + obj + " use time=" + (end - start));
		return obj;
	}

	public boolean setAttribute(String id, Object obj, long expireTime) {
		long start = System.currentTimeMillis();
		boolean flag = false;
		if (useflag) {
			getMemCachedClient();
			if (expireTime > 0)
				flag = mcc.set(id, obj, new Date(expireTime));
			else
				flag = mcc.set(id, obj);
		}
		long end = System.currentTimeMillis();
		log.debug("set id=" + id + "   flag=" + flag + " use time="	+ (end - start));
		if (flag == false) {
			log.error("set id=" + id + " flag=" + flag + " use time=" + (end - start));
		}
		return flag;
	}
	/*带版本号缓存*/
	public boolean setAttribute(String id,String v,Object obj, long expireTime) {
		long start = System.currentTimeMillis();
		boolean flag = false;
		if (useflag) {
			getMemCachedClient();
			Map mr=(Map)mcc.get(id);
			if(null==mr) 
				mr=new HashMap();
			mr.put(v, obj);
			if (expireTime > 0)
				flag = mcc.set(id, mr, new Date(expireTime));
			else
				flag = mcc.set(id, mr);
		}
		long end = System.currentTimeMillis();
		log.debug("set id=" + id + "   flag=" + flag + " use time="	+ (end - start));
		if (flag == false) {
			log.error("set id=" + id + " flag=" + flag + " use time=" + (end - start));
		}
		return flag;
	}

	public boolean setAttribute(String id, Object obj) {
		return this.setAttribute(id, obj, new Date().getTime() + sessionTimeout);
	}
	/*带版本号缓存*/
	public boolean setAttribute(String id,String v, Object obj) {
		return this.setAttribute(id, v,obj, new Date().getTime() + sessionTimeout);
	}

	public boolean removeAttribute(String id) {
		getMemCachedClient();
		return mcc.delete(id);
	}

	@SuppressWarnings("unchecked")
	public Map<String, Map<String, String>> stats() {
		getMemCachedClient();
		return mcc.stats();
	}

	private static void getMemCachedClient() {

		if (mcc == null) {
			mcc = new MemCachedClient(poolName);
			// mcc.setPoolName(poolName);

			// mcc.setCompressEnable(false);
			// mcc.setCompressThreshold(0);
		}
	}

	protected void finalize() {
		if (pool != null) {
			pool.shutDown();
		}
	}

	public boolean isNotConnection() {
		return isNotConnection;
	}

	protected static class InnerConvertUtil {
		public static int getIntProperty(Properties props, String key) {
			return getIntProperty(props, key, 0);
		}

		public static int getIntProperty(Properties props, String key,
				int defaultValue) {
			int result = defaultValue;
			if (props != null) {
				String value = props.getProperty(key);
				try {
					result = Integer.parseInt(value);
				} catch (Exception ex) {
					log.error("get property fail:" + ex.getMessage());
				}
			}
			return result;
		}

		public static long getLongProperty(Properties props, String key) {
			return getLongProperty(props, key, 0);
		}

		public static long getLongProperty(Properties props, String key,
				long defaultValue) {
			long result = defaultValue;
			if (props != null) {
				String value = props.getProperty(key);
				try {
					result = Long.parseLong(value);
				} catch (Exception ex) {
					log.warn("get property fail:" + ex.getMessage());
				}
			}
			return result;
		}

		public static boolean getBooleanProperty(Properties props, String key) {
			return getBooleanProperty(props, key, false);
		}

		public static boolean getBooleanProperty(Properties props, String key,
				boolean defaultValue) {
			boolean result = defaultValue;
			if (props != null) {
				String value = props.getProperty(key);
				try {
					result = Boolean.parseBoolean(value);
				} catch (Exception ex) {
					log.warn("get property fail:" + ex.getMessage());
				}
			}
			return result;
		}
	}

	public static void main(String args[]) throws Exception {
		boolean var = MemcachedUtil.getInstance().setAttribute("1", "test1");
		if(!var){
			throw new Exception("MemCacheException");
		}
		System.out.println(MemcachedUtil.getInstance().getAttribute("1"));
	}
}
